/*
 * Copyright (C) 2010 Seapeak.Xu
 *
 * fostmq may be copied only under the terms of the GNU General
 * Public License V3, which may be found in the fostmq source kit.
 *
 * Created on: 2010-8-20
 * Author: Seapeak.Xu
 */

#include <stdlib.h>
#include <stdio.h>
#include <tcbdb.h>
#include <unistd.h>
#include <tcbdb.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

#include "fost_logger.h"
#include "fost_taskpool.h"
#include "fost_buff.h"
#include "fost_msg.h"
#include "fostmq_protocol.h"
#include "fost_event.h"
#include "fost_mgnb.h"
#include "fost_typedef.h"
#include "fost_mem.h"
#include "fost_io.h"
#include "fost_string.h"
#include "fost_thread.h"
#include "fost_timer.h"
#include "fostmq_conf.h"

struct database
{
	pthread_mutex_t locker;
	TCBDB *db;
};

struct timer_thread
{
	int sec;
	int usec;
	elapsedhandler callback;
	void *arg;
};

static struct  database *_storage;

static int get_pop_pos(const char *name);
static int get_push_pos(const char *name);
static int set_pop_pos(const char *name, int pos);
static int set_push_pos(const char *name, int pos);
static void timer_callback(void *arg);
static void *thread_timer_callback(void *arg);

static int push_by_id(task_t *task);
static int push_by_name(task_t *task);
static int pop_by_id(task_t *task);
static int pop_by_name(task_t *task);
static int delete_by_id(task_t *task);
static int heart_beat(task_t *task);
static int destroy_queue(task_t *task);
static int pop_and_delete_by_id(task_t *task);

//only the way for thread
static struct timer_thread data;	

int service_init(const char *storepath, const size_t nonleafnodes,
		const size_t chucksize, const size_t synctime)
{
	int result = 0;
	if (0 != (result = mkdir_cascading(storepath, 777)))
	{
		log_error("File:%s,Line:%d,Function:%s.create the database path is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
		return result;
	}

	_storage = (struct database *) fost_calloc1(sizeof(struct database));
	if(NULL == _storage)
	{
		result = errno;
		log_error("File:%s,Line:%d,Function:%s.malloc memory is fail.Errno:%d,Info:%s.",
				__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
		return result;
	}
	do
	{
		if(0 != (result = thread_mutexlocker_init(&(_storage->locker))))
		{
			log_error("File:%s,Line:%d,Function:%s.init mutex locker is fail.Error:%d,info:%s.",
					__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
			break;
		}
		_storage->db = tcbdbnew();
		if(NULL == _storage->db)
		{
			result = errno;
			log_error("File:%s,Line:%d,Function:%s.create db with tc is fail.Error:%d,Info:%s.",
					__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
			pthread_mutex_destroy(&(_storage->locker));
			break;
		}

		char path[PATH_LEN];
		memset(path,'\0',PATH_LEN);

		snprintf(path, PATH_LEN - 1, "%s/%s", storepath, "fostmq.db");
		tcbdbtune(_storage->db, 1024, 2048, 50000000, 8, 10, BDBTLARGE);
		tcbdbsetcache(_storage->db, nonleafnodes * 2, nonleafnodes);
		tcbdbsetxmsiz(_storage->db, chucksize);

		if (!tcbdbopen(_storage->db, path, BDBOWRITER | BDBOCREAT))
		{
			result = tcbdbecode(_storage->db);
			log_error("File:%s,Line:%d,Function:%s.open the fastmq database is error.Errno:%d,Info:%s.",
					__FILE__, __LINE__, __FUNCTION__, result, tcbdberrmsg(result));
			break;
		}

		data.sec = 0 >= synctime ? 30 : synctime;
		data.usec = 0;//now the usec is not must
		data.callback = timer_callback;//dizzy with pointer now ?! haha!
		data.arg = NULL;
		create_working_thread(thread_timer_callback,&data);

	}while(false);
	if(0 != result)
	{
		FOST_FREE(_storage);
	}
	return result;
}

void deal_request_header(void *arg)
{
	if (NULL == arg)
	{
		log_error("File:%s,Line:%d,Function:%s.the argument is null.",
				__FILE__, __LINE__, __FUNCTION__);
		return;
	}
	task_t *task = (task_t *) arg;
	buff2header(&(task->req_header), task->req_headerbuff);
	return;
}

void deal_request_body(void *arg)
{
	if (NULL == arg)
	{
		log_error("File:%s,Line:%d,Function:%s.the argument is null.",
				__FILE__, __LINE__, __FUNCTION__);
		return;
	}
	task_t *task = (task_t *) arg;

	int result;
	switch (task->req_header.protocol)
	{
		case PUSHBYID :
			{
				result = push_by_id(task);
				task->resp_header.protocol = PUSHBYID;
				task->resp_header.state = result;
				break;
			}
		case PUSHBYNAME :
			{
				result = push_by_name(task);
				task->resp_header.protocol = PUSHBYNAME;
				task->resp_header.state = result;
				break;
			}
		case POPBYID :
			{
				result = pop_by_id(task);
				task->resp_header.protocol = POPBYID;
				task->resp_header.state = result;
				break;
			}
		case POPBYNAME :
			{
				result = pop_by_name(task);
				task->resp_header.protocol = POPBYNAME;
				task->resp_header.state = result;
				break;
			}
		case DELETEBYID :
			{
				result = delete_by_id(task);
				task->resp_header.protocol = DELETEBYID;
				task->resp_header.state = result;
				break;
			}
		case POPDELBYID:
			{
				result = pop_and_delete_by_id(task);
				task->resp_header.protocol = POPDELBYID;
				task->resp_header.state = result;
				break;
			}
		case DESTROYQUEUE :
			{
				result = destroy_queue(task);
				task->resp_header.protocol = DESTROYQUEUE;
				task->resp_header.state = result;
				break;
			}
		case HEARTBEAT :
			{
				result = heart_beat(task);
				task->resp_header.protocol = HEARTBEAT;
				task->resp_header.state = result;
				break;
			}
		default :
			{
				task->resp_header.protocol = 0;
				task->resp_header.state = -1;
				break;
			}
	}

	task->offset = 0;
	task->session_type = header;
	memset(task->resp_headerbuff, 0, HEADERLEN + 1);
	header2buff(&(task->resp_header), task->resp_headerbuff);

	server_response_event(task->sock, EV_WRITE, task);

	if (-1 == result)
	{
		log_error("File:%s,Line:%d,Function:%s.real request event is error.",
				__FILE__, __LINE__, __FUNCTION__);
	}

	return;
}

static int get_pop_pos(const char *name)
{
	char fullname[QUEUE_NAME_LEN];
	memset(fullname,'\0',QUEUE_NAME_LEN);
	int pos = 0;
	snprintf(fullname, QUEUE_NAME_LEN - 1, "%s_%s", name, "poppos");
	char *value = tcbdbget2(_storage->db, fullname);
	
	if (NULL == value)
	{
		return 0;//default is 0
	}
	pos = atoi(value);
	FOST_FREE(value);
	return g_namedqueue_message_size < pos ? 0 : pos;
}
static int get_push_pos(const char *name)
{
	char fullname[QUEUE_NAME_LEN];
	memset(fullname,'\0',QUEUE_NAME_LEN);
	int pos = 0;
	snprintf(fullname, QUEUE_NAME_LEN - 1, "%s_%s", name, "pushpos");
	char *value = tcbdbget2(_storage->db, fullname);
	if (NULL == value)
	{
		return 0;//default is 0
	}
	pos = atoi(value);
	FOST_FREE(value);
	return g_namedqueue_message_size < pos ? 0 : pos;
}

static int set_pop_pos(const char *name, int pos)
{
	int result = 0;
	char fullname[QUEUE_NAME_LEN];
	memset(fullname,'\0',QUEUE_NAME_LEN);
	char value[INT_LEN];
	memset(value,'\0',INT_LEN);
	snprintf(fullname, QUEUE_NAME_LEN - 1, "%s_%s", name, "poppos");
	snprintf(value, INT_LEN - 1 , "%d", pos);

	if (tcbdbput2(_storage->db, fullname, value))
	{
		tcbdbsync(_storage->db);
	}
	else
	{
		result = tcbdbecode(_storage->db);
		log_error("File:%s,Line:%d,Function:%s.overwrite the %s pop pos is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, name, result,tcbdberrmsg(result));
	}
	return result;
}

static int set_push_pos(const char *name, int pos)
{
	int result = 0;
	char fullname[QUEUE_NAME_LEN];
	memset(fullname,'\0',QUEUE_NAME_LEN);
	char value[INT_LEN];
	memset(value,'\0',INT_LEN);
	snprintf(fullname, QUEUE_NAME_LEN - 1, "%s_%s", name, "pushpos");
	snprintf(value, INT_LEN - 1, "%d", pos);

	if (tcbdbput2(_storage->db, fullname, value))
	{
		tcbdbsync(_storage->db);
	}
	else
	{
		result = tcbdbecode(_storage->db);
		log_error("File:%s,Line:%d,Function:%s.overwrite the %s pop pos is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__,name, result,tcbdberrmsg(result));
	}
	return result;
}

static int push_by_id(task_t *task)
{
	int result = 0;
	if(0 == task->req_header.bodylen)
	{
		log_error("File:%s,Line:%d,Function:%s.the deal body_length is 0.",
				__FILE__,__LINE__,__FUNCTION__);
		return ENODATA;
	}

	int namelen = 0;
	int valuelen = 0;
	char *name;
	char *value;
	namelen = buff2int(task->req_bodybuff);
	valuelen = task->req_header.bodylen - namelen - sizeof(int);
	name = fost_callocs(namelen);
	if (NULL == name)
	{
		result = errno;
		log_error("File:%s,Line:%d,Function:%s.malloc the memory is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
		return result;
	}

	do
	{
		value = fost_callocs(valuelen);
		if (NULL == value)
		{
			result = errno;
			log_error("File:%s,Line:%d,Function:%s.malloc the memory is error.Errno:%d,Info:%s.",
					__FILE__, __LINE__, __FUNCTION__, result,strerror(result));
			break;
		}
		do
		{
			memcpy(name, task->req_bodybuff + sizeof(int),namelen);
			*(name + namelen) = '\0';

			memcpy(value, task->req_bodybuff + sizeof(int) + namelen,valuelen);
			*(value + valuelen) = '\0';
			if(0 != (result = pthread_mutex_lock(&(_storage->locker))))
			{
				log_error("File:%s,Line:%d,Function:%s.get storage mutex locker is fail.Errno:%d,Info:%s.",
						__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
				break;
			}
			do
			{
				if (!tcbdbput2(_storage->db, name, value))
				{
					result = tcbdbecode(_storage->db);
					log_error("File:%s,Line:%d,Function:%s.push the message into mq is error.Errno:%d,Info:%s.",
							__FILE__, __LINE__, __FUNCTION__, result,tcbdberrmsg(result));
					break;
				}
			}while(false);
			pthread_mutex_unlock(&(_storage->locker));
		} while (false);
		FOST_FREE(value);
	} while (false);
	FOST_FREE(name);
	task->resp_header.bodylen = 0;
	return result;
}

static int push_by_name(task_t *task)
{
	if(0 == task->req_header.bodylen)
	{
		log_error("File:%s,Line:%d,Function:%s.the deal body_length is 0.",
				__FILE__,__LINE__,__FUNCTION__);
		return ENODATA;
	}
	int result = 0;
	int namelen = 0;
	int valuelen = 0;
	char *name;
	char *value;
	namelen = buff2int(task->req_bodybuff);
	valuelen = task->req_header.bodylen - namelen - sizeof(int);

	name = fost_callocs(namelen);
	if (NULL == name)
	{
		result = errno;
		log_error("File:%s,Line:%d,Function:%s.malloc the memory is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
		return result;
	}

	do
	{
		value = fost_callocs(valuelen);
		if (NULL == value)
		{
			result = errno;
			log_error("File:%s,Line:%d,Function:%s.malloc the memory is error.Errno:%d,Info:%s.",
					__FILE__, __LINE__, __FUNCTION__, result,strerror(result));
			break;
		}
		do
		{
			memcpy(name, task->req_bodybuff + sizeof(int),namelen);
			*(name + namelen) = '\0';
			memcpy(value, task->req_bodybuff + sizeof(int) + namelen, valuelen);
			*(value + valuelen) = '\0';

			if (0 != (result = pthread_mutex_lock(&(_storage->locker))))
			{
				result = errno;
				log_error("File:%s,Line:%d,Function:%s.get the mutex locker is error.Errno:%d,Info:%s.",
						__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
				break;
			}
			do
			{
				int pos = get_push_pos(name);
				char fullname[QUEUE_NAME_LEN];
				memset(fullname,'\0',QUEUE_NAME_LEN);
				snprintf(fullname,QUEUE_NAME_LEN - 1,"%s_%d", name,pos);
				*(fullname + (QUEUE_NAME_LEN - 1)) = '\0';
				if (!tcbdbput2(_storage->db,fullname,value))
				{
					result = tcbdbecode(_storage->db);
					log_error("File:%s,Line:%d,Function:%s.push the message into mq is error.Errno:%d,Info:%s.",
							__FILE__,__LINE__,__FUNCTION__,result,tcbdberrmsg(result));
					break;
				}
				set_push_pos(name, pos + 1);
			} while (false);
			pthread_mutex_unlock(&(_storage->locker));
		} while (false);
		FOST_FREE(value);
	} while (false);
	FOST_FREE(name);

	task->resp_header.bodylen = 0;
	return result;
}

static int pop_by_id(task_t *task)
{
	if(0 == task->req_header.bodylen)
	{
		log_error("File:%s,Line:%d,Function:%s.the deal body_length is 0.",
				__FILE__,__LINE__,__FUNCTION__);
		return ENODATA;
	}
	int result = 0;
	if(0 != (result = pthread_mutex_lock(&(_storage->locker))))
	{
		log_error("File:%s,Line:%d,Function:%s.get storage mutex locker is fail.Errno:%d,Info:%s.",
				__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
		return result;
	}
	char *value = tcbdbget2(_storage->db, task->req_bodybuff);
	if (NULL == value)
	{
		result = tcbdbecode(_storage->db);
		log_warn("File:%s,Line:%d,Function:%s.get queue value is error.Info:queue name:%s,Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, task->req_bodybuff, result,tcbdberrmsg(result));
		FOST_FREE(task->req_bodybuff);
		task->resp_header.bodylen = 0;
		pthread_mutex_unlock(&(_storage->locker));
		return result;
	}

	pthread_mutex_unlock(&(_storage->locker));

	do
	{
		task->resp_header.bodylen = strlen(value);
		FOST_FREE(task->req_bodybuff);
		task->resp_bodybuff = fost_callocs(task->resp_header.bodylen + 1);
		if (NULL == task->resp_bodybuff)
		{
			result = errno;
			log_error("File:%s,Line:%d,Function:%s.malloc memory is error.Errno:%d,Info:%s.",
					__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
			task->resp_header.bodylen = 0;
			break;
		}

		memcpy(task->resp_bodybuff, value, task->resp_header.bodylen);
		*(task->resp_bodybuff + task->resp_header.bodylen) = '\0';
	} while (false);
	FOST_FREE(value);
	return result;
}


static int pop_and_delete_by_id(task_t *task)
{
	if(0 == task->req_header.bodylen)
	{
		log_error("File:%s,Line:%d,Function:%s.the deal body_length is 0.",
				__FILE__,__LINE__,__FUNCTION__);
		return ENODATA;
	}
	int result = 0;
	if(0 != (result = pthread_mutex_lock(&(_storage->locker))))
	{
		log_error("File:%s,Line:%d,Function:%s.get storage mutex locker is fail.Errno:%d,Info:%s.",
				__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
		return result;
	}
	char *value = tcbdbget2(_storage->db, task->req_bodybuff);
	if (NULL == value)
	{
		result = tcbdbecode(_storage->db);
		log_warn("File:%s,Line:%d,Function:%s.get queue value is error.Info:queue name:%s,Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, task->req_bodybuff, result,tcbdberrmsg(result));
		FOST_FREE(task->req_bodybuff);
		task->resp_header.bodylen = 0;
		pthread_mutex_unlock(&(_storage->locker));
		return result;
	}
	if (!tcbdbout2(_storage->db, task->req_bodybuff))
	{
		result = tcbdbecode(_storage->db);
		log_warn("File:%s,Line:%d,Function:%s.delete id:%s message is error.Errno:%d,Info:%s",
			__FILE__, __LINE__, __FUNCTION__,task->req_bodybuff,result,tcbdberrmsg(result));
	}

	pthread_mutex_unlock(&(_storage->locker));

	do
	{
		task->resp_header.bodylen = strlen(value);
		FOST_FREE(task->req_bodybuff);
		task->resp_bodybuff = fost_callocs(task->resp_header.bodylen + 1);
		if (NULL == task->resp_bodybuff)
		{
			result = errno;
			log_error("File:%s,Line:%d,Function:%s.malloc memory is error.Errno:%d,Info:%s.",
					__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
			task->resp_header.bodylen = 0;
			break;
		}

		memcpy(task->resp_bodybuff, value, task->resp_header.bodylen);
		*(task->resp_bodybuff + task->resp_header.bodylen) = '\0';
	} while (false);
	FOST_FREE(value);
	return result;
}



static int pop_by_name(task_t *task)
{
	if(0 == task->req_header.bodylen)
	{
		log_error("File:%s,Line:%d,Function:%s.the deal body_length is 0.",
				__FILE__,__LINE__,__FUNCTION__);
		return ENODATA;
	}
	int result = 0;
	int namelen = 0;
	int valuelen = 0;
	char *name;
	char *value;
	namelen = task->req_header.bodylen;
	name = fost_callocs(namelen);
	if (NULL == name)
	{
		result = errno;
		log_error("File:%s,Line:%d,Function:%s.malloc the memory is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
		return result;
	}
	do
	{
		memcpy(name, task->req_bodybuff, namelen);
		*(name + namelen) = '\0';

		if (0 != (result = pthread_mutex_lock(&(_storage->locker))))
		{
			result = errno;
			log_error("File:%s,Line:%d,Function:%s.get the locker is error.Errno:%d,Info:%s",
					__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
			break;
		}
		do
		{
			int poppos, pushpos;
			poppos = get_pop_pos(name);
			pushpos = get_push_pos(name);

			char fullname[QUEUE_NAME_LEN];
			do
			{
				memset(fullname,'\0',QUEUE_NAME_LEN);
				snprintf(fullname, QUEUE_NAME_LEN - 1, "%s_%d",name, poppos);
				value = tcbdbget2(_storage->db,fullname);
				poppos += 1;
			} while (NULL == value && poppos < pushpos);

			if (NULL == value)//when pop queue is last element
			{
				result = tcbdbecode(_storage->db);
				if (poppos == pushpos)
				{
					set_pop_pos(name, 0);
					set_push_pos(name, 0);
				}
				log_warn("File:%s,Line:%d,Function:%s.get the queue:%s is null.",
						__FILE__, __LINE__, __FUNCTION__,name);
				task->resp_header.bodylen = 0;
				task->resp_header.state = result;
				break;
			}
			do
			{
				valuelen = strlen(value);
				FOST_FREE(task->req_bodybuff);
				task->resp_bodybuff = fost_callocs(valuelen);
				if (NULL == task->resp_bodybuff)
				{
					result = errno;
					log_error("File:%s,Line:%d,Function:%s.malloc memory is error.Errno:%d,Info:%s.",
							__FILE__, __LINE__, __FUNCTION__, result,strerror(result));
					task->resp_header.bodylen = 0;
					break;
				}

				memcpy(task->resp_bodybuff, value,valuelen);
				*(task->resp_bodybuff + valuelen) = '\0';
				task->resp_header.bodylen = valuelen;

				if (poppos == pushpos)
				{
					set_pop_pos(name, 0);
					set_push_pos(name, 0);
				}
				else
				{
					set_pop_pos(name, poppos);
				}

				if (!tcbdbout2(_storage->db, fullname))
				{
					result = tcbdbecode(_storage->db);
					log_warn("File:%s,Line:%d,Function:%s.delete message is error.Errno:%d,Info:%s",
							__FILE__, __LINE__, __FUNCTION__, result,tcbdberrmsg(result));
				}
			} while (false);
			FOST_FREE(value);
		} while (false);
		pthread_mutex_unlock(&(_storage->locker));

	} while (false);
	FOST_FREE(name);
	return result;
}

static int delete_by_id(task_t *task)
{
	if(0 == task->req_header.bodylen)
	{
		log_error("File:%s,Line:%d,Function:%s.the deal body_length is 0.",
				__FILE__,__LINE__,__FUNCTION__);
		return ENODATA;
	}

	int result = 0;
	if(0 != (result = pthread_mutex_lock(&(_storage->locker))))
	{
		log_error("File:%s,Line:%d,Function:%s.get storage locker is fail.Errno:%d,Info:%s.",
				__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
		return result;
	}
	do
	{
		if (!tcbdbout2(_storage->db, task->req_bodybuff))
		{
			result = tcbdbecode(_storage->db);
			log_error("File:%s,Line:%d,Function:%s.delete the queue from mq is error.Queue name:%s,Errno:%d,Info:%s.",
					__FILE__, __LINE__, __FUNCTION__, task->req_bodybuff, result,tcbdberrmsg(result));
		}
	}while(false);
	pthread_mutex_unlock(&(_storage->locker));

	task->resp_header.bodylen = 0;
	return result;
}

static int heart_beat(task_t *task)
{
	task->resp_header.bodylen = 0;
	return 0;
}

static int destroy_queue(task_t *task)
{
	int result = 0;
	if (0 != (result = pthread_mutex_lock(&(_storage->locker))))
	{
		log_error("File:%s,Line:%d,Function:%s.get the locker is error.Errno:%d,Info:%s.",
				__FILE__, __LINE__, __FUNCTION__, result, strerror(result));
		task->resp_header.bodylen = 0;
		return result;
	}
	do
	{
		set_push_pos(task->req_bodybuff, 0);
		set_pop_pos(task->req_bodybuff, 0);
		task->resp_header.bodylen = 0;
	} while (false);
	pthread_mutex_unlock(&(_storage->locker));
	return result;
}

static void *thread_timer_callback(void *arg)
{
	if(NULL == arg)
	{
		log_error("File:%s,Line:%d,Function:%s.the timer thread callback arg is null.",
				__FILE__,__LINE__,__FUNCTION__);
		return NULL;
	}
	struct timer_thread *data = (struct timer_thread *) arg;
	timer(data->sec,data->usec,data->callback,data->arg);
	return NULL;
}

static void timer_callback(void *arg)
{
	int result = 0;
	if(0 != (result = pthread_mutex_lock(&(_storage->locker))))
	{
		log_error("File:%s,Line:%d,Function:%s.get mutex locker is fail.Error:%d,Info:%s.",
				__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
		return;
	}
	tcbdbsync(_storage->db);
	pthread_mutex_unlock(&(_storage->locker));
}

int service_destroy(void)
{
	int result = 0;
	if(0 != (result = pthread_mutex_lock(&(_storage->locker))))
	{
		log_error("File:%s,Line:%d,Function:%s.get mutex locker is fail.Error:%d,Info:%s.",
				__FILE__,__LINE__,__FUNCTION__,result,strerror(result));
		return result;
	}

	tcbdbsync(_storage->db);
	pthread_mutex_unlock(&(_storage->locker));
	tcbdbclose(_storage->db);
	return 0;
}

void sync_queue()
{
	tcbdbsync(_storage->db);
}
